#include "auxiliar.h"

static int ultimoDia[12] = { 31, 28, 31, 30, 31, 30, 31, 31,30, 31, 30, 31 };
static int ultimoDiaB[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

void printComando(Comando* cmd){
    fprintf(stdout, "# Estrutura\n#----------------\n#%s\n#%d\n#%s\n#%s\n#%s\n#",
        cmd->host, cmd->porta,cmd->usuario,cmd->senha,cmd->comandos);
}

// Função que valida se o que está sendo tratado é realmente um número.
void isNumero(const char* asciiNum){
    if ( *asciiNum < '0' || *asciiNum > '9' ){
        fprintf(stdout, ERRO_MSG, 7, ERRO_07);
        exit(7);
    }
}

// Função que valida as Datas
void validaData(const char *data){
    int dia, mes, ano, count;
    char d[] = {'\0','\0','\0','\0','\0'};
    if ( strlen(data) != 8 ){
        fprintf(stdout, ERRO_MSG, 3, ERRO_03);
        exit(3);
    }
    
    for ( count = 0 ; count < 8 ; isNumero(&data[count]),count++ );

    d[0] = data[0]; d[1] = data[1];
    dia = atoi(d);

    d[0] = data[2]; d[1] = data[3];
    mes = atoi(d);

    d[0] = data[4]; d[1] = data[5]; d[2] = data[6]; d[3] = data[7];
    ano = atoi(d);

    if (dia < 1 || dia > 31 || mes < 1 || mes > 12 || ano < 1){
        fprintf(stdout, ERRO_MSG, 3, ERRO_03);
        exit(3);
    }

    if ((ano % 4 == 0) && (ano % 400 == 0 || ano % 100 != 0))
        if (ultimoDiaB[mes - 1] >= dia)
            return;

    if (ultimoDia[mes - 1] >= dia)
        return;

    fprintf(stdout, ERRO_MSG, 3, ERRO_03);
    exit(3);
}

// Função que valida horas no formato adequado.
// E retorna a quantidade de minutos.
int validaHora(const char *hora){
    int h, m, count;
    char d[] = {'\0','\0','\0'};
    if ( strlen(hora) != 4 ){
        fprintf(stdout, ERRO_MSG, 4, ERRO_04);
        exit(4);
    }

    for ( count = 0 ; count < 4 ; isNumero(&hora[count]),count++ );

    d[0] = hora[0]; d[1] = hora[1];
    h = atoi(d);

    d[0] = hora[2]; d[1] = hora[3];
    m = atoi(d);

    //printf("Hora %d, minuto %d\n",h,m);

    if ( h >= 24 || h < 0 || m > 59 || m < 0){
        fprintf(stdout, ERRO_MSG, 4, ERRO_04);
        exit(4);
    }

    return (h*60)+m;
}

// Comando para adicionar uma entrada na Agenda.
void comandoAdd(Comando* comando, const char* data, const char* horaInicio,
                const char* horaFim, const char* mensagem){
    fprintf(stdout, "# Comando de ADD\n");

    validaData(data);
    
    if ( validaHora(horaFim)-validaHora(horaInicio) <= 0 ) {
        fprintf(stdout, ERRO_MSG, 5 , ERRO_05);
        exit(5);
    }

    sprintf(comando->comandos, "%d;%s;%s;%s;%s;%s;%s;",2,comando->usuario,
            comando->senha,data,horaInicio,horaFim,mensagem);
}

// Comando para Remover todas as entradas de uma determinada data.
void comandoRemoveAll(Comando* comando,const char* data){
    validaData(data);
    fprintf(stdout, "# Comando de REMOVE ALL para a DATA [ %s ].\n",data);
    sprintf(comando->comandos, "%d;%s;%s;%s;",3,comando->usuario,
            comando->senha,data);   
}

// Comando para Remover uma determinada entrada para uma determinada data.
void comandoRemove(Comando* comando, const char* data, const char* hora){
    validaData(data);
    validaHora(hora);
    fprintf(stdout, "# Comando de REMOVE para a HORA [ %s ] do DIA [ %s ] .\n",hora,data);
    sprintf(comando->comandos, "%d;%s;%s;%s;%s;",4,comando->usuario,
            comando->senha,data,hora);   
}

// Comando para atualizar uma entrada na Agenda.
void comandoUpdate(Comando* comando, const char* data, const char* horaInicio,
                const char* horaFim, const char* mensagem){
    fprintf(stdout, "# Comando de UPDATE\n");

    validaData(data);

    if ( validaHora(horaFim)-validaHora(horaInicio) <= 0 ) {
        fprintf(stdout, ERRO_MSG, 5 , ERRO_05);
        exit(5);
    }

    sprintf(comando->comandos, "%d;%s;%s;%s;%s;%s;%s;",5,comando->usuario,
            comando->senha,data,horaInicio,horaFim,mensagem);
}

// Comando para Obter todas as entradas de uma determinada data.
void comandoGetAll(Comando* comando,const char* data){
    validaData(data);
    fprintf(stdout, "# Comando de GET ALL para a DATA [ %s ].\n",data);
    sprintf(comando->comandos, "%d;%s;%s;%s;",7,comando->usuario,
            comando->senha,data);   
}

// Comando para Obter uma determinada entrada para uma determinada data.
void comandoGet(Comando* comando, const char* data, const char* hora){
    validaData(data);
    validaHora(hora);
    fprintf(stdout, "# Comando de GET para a HORA [ %s ] do DIA [ %s ] .\n",hora,data);
    sprintf(comando->comandos, "%d;%s;%s;%s;%s;",6,comando->usuario,
            comando->senha,data,hora);   
}


/********************************************************************
*  Função que verifica se o login do cara está no formato adequado  *
*  exemplo: todas as letras minusculas, o primeiro caracter deve    *
*  ser um alphanumérico, o restante pode ser qualquer coisa,        *
*  ainda deve-se ter um ponto separador no meio.                    *
*  O ideal para username é <nome>.<sobrenome>                       * 
*********************************************************************/
int matchUsername(const char *userName)
{
    regex_t re;
    int status, size;
    char* patternUserName = "^[a-z][a-z0-9]*\\.[a-z0-9]+$";

    size = strlen(userName);
    if ( size > 20 || size <= 0 )
        return 0;

    if(regcomp(&re, patternUserName, REG_EXTENDED|REG_NOSUB) != 0)
        return 0;

    status = regexec(&re, userName, (size_t)0, NULL, 0);

    regfree(&re);

    if(status != 0) 
        return 0;

    return 1;
}

/***********************************************************
 *  Trata de formatar as mensagens de retorno do servidor  *
 *  As mensagens padrão.                                   *
 ***********************************************************/
void handlerRetorno(char *buf, const char *operacao){
    char retorno[4];
    int index, tipo;
    memset(retorno, 0, 4);
    
    for ( index = 0 ; buf[index] != ';' && index < 4 && buf[index] != '\0' ; retorno[index] = buf[index], index++ );

    tipo = atoi(retorno);

    if ( tipo != 200 ){
        fprintf(stdout, "A Operação de [%s] resultou no erro [%d] do tipo [%s].\n", operacao , tipo, &buf[index+1]);
        exit(-1);
    }
    
    fprintf(stdout, "Operação de [%s] - Realizada com Sucesso - [%d] - SV Resposta = [%s]\n", operacao, tipo, &buf[index+1]);
}

/***********************************************************
 *  Trata de formatar as mensagens de retorno do servidor  *
 *  As mensagens do tipo GET                               *
 ***********************************************************/
void handlerRetornoGet(char *buf, const char *operacao){
    char retorno[4];
    int index, tipo, pos;
    memset(retorno, 0, 4);
    
    for ( index = 0 ; buf[index] != ';' && index < 4 && buf[index] != '\0' ; index++ )
        retorno[index] = buf[index];

    tipo = atoi(retorno);

    if ( tipo != 200 ){
        fprintf(stdout, "A Operação de [%s] resultou [%d] que significa [%s].\n", operacao , tipo, &buf[index+1]);
        exit(-1);
    }
    
    index++;
    pos = index;
    while(buf[++index] != ';');
    buf[index] = '\0';
    fprintf(stdout, "No dia [%s] ",&buf[pos]);

    pos = index+1;
    while(buf[++index] != ';');
    buf[index] = '\0';
    fprintf(stdout, "comecando às [%s] ",&buf[pos]);

    pos = index+1;
    while(buf[++index] != ';');
    buf[index] = '\0';
    fprintf(stdout, "e terminando às [%s] ",&buf[pos]);
    
    pos = index+1;
    while(buf[++index] != ';');
    buf[index] = '\0';
    fprintf(stdout, "você tem que [%s]\n",&buf[pos]);

}

/***********************************************************
 *  Trata de formatar as mensagens de retorno do servidor  *
 *  Pega a quantidade de que o GETALL encontrou.           *
 ***********************************************************/
int handlerRetornoGetAllQtde(char *buf, const char *operacao){
    char retorno[4];
    int index, tipo, pos, qtde;
    memset(retorno, '\0', 4);
    
    for ( index = 0 ; buf[index] != ';' && index < 4 && buf[index] != '\0' ; index++ )
        retorno[index] = buf[index];

    tipo = atoi(retorno);

    if ( tipo != 200 ){
        fprintf(stdout, "A Operação de [%s] retornou [%d] que significa [%s].\n", operacao , tipo, &buf[index+1]);
        exit(-1);
    }

    index++;
    memset(retorno, 0, 4);

    for ( pos = 0 ; buf[index] != ';' ; index++, pos++ )
        retorno[pos] = buf[index];

    qtde = atoi(retorno);
   
    fprintf(stdout, "No dia [%s] encotramos [%d] eventos para você.\n",&buf[index+1], qtde);
    
    if(qtde%4 == 0)
        return qtde/4;
    else
        return (qtde/4)+1;

}

/***********************************************************
 *  Trata de formatar as mensagens de retorno do servidor  *
 *  Logica burra para GETALL.                              *
 ***********************************************************/
void handlerRetornoGetAll(char *buf){
    int index, pos;

    index = pos = 0;
   do
    {

        for ( ; buf[index]!=';' ; index++ );
        buf[index] = '\0';
        fprintf(stdout, "das [%s] ",&buf[pos]);
        pos = ++index;

        for ( ; buf[index]!=';' ; index++ );
        buf[index] = '\0';
        fprintf(stdout, "às [%s] - ",&buf[pos]);
        pos = ++index;

        for ( ; buf[index]!=';' && buf[index]!='\0' ; index++ );
        if( buf[index]=='\0'){
            fprintf(stdout, "[%s]\n",&buf[pos]);
            break;
        }
        buf[index] = '\0';
        fprintf(stdout, "[%s]\n",&buf[pos]);
        pos = ++index;
        
    }
    while(1);

}
